from fastapi import Request, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from typing import Optional, Dict, Any
import time
import jwt
import os
from dotenv import load_dotenv
from utils.logger import app_logger

# 加载环境变量
load_dotenv()

# JWT配置
JWT_SECRET = os.getenv("JWT_SECRET", "your-secret-key")
JWT_ALGORITHM = os.getenv("JWT_ALGORITHM", "HS256")
JWT_EXPIRATION = int(os.getenv("JWT_EXPIRATION", "3600"))  # 默认1小时

class JWTBearer(HTTPBearer):
    """
    JWT认证中间件
    """
    def __init__(self, auto_error: bool = True):
        super(JWTBearer, self).__init__(auto_error=auto_error)
    
    async def __call__(self, request: Request) -> Dict[str, Any]:
        """
        验证JWT令牌
        """
        credentials: HTTPAuthorizationCredentials = await super(JWTBearer, self).__call__(request)
        
        if not credentials:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="无效的认证凭据"
            )
            
        if credentials.scheme != "Bearer":
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="无效的认证方案"
            )
            
        payload = self.verify_jwt(credentials.credentials)
        if not payload:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="无效的令牌或已过期"
            )
            
        return payload
    
    def verify_jwt(self, token: str) -> Optional[Dict[str, Any]]:
        """
        验证JWT令牌
        
        参数:
            token (str): JWT令牌
            
        返回:
            Optional[Dict[str, Any]]: 如果验证成功，返回令牌载荷；否则返回None
        """
        try:
            payload = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM])
            
            # 验证令牌是否过期
            if payload.get("exp") and time.time() > payload["exp"]:
                app_logger.warning(f"令牌已过期: {payload}")
                return None
                
            return payload
        except Exception as e:
            app_logger.error(f"验证令牌时出错: {e}")
            return None

def create_token(data: Dict[str, Any]) -> str:
    """
    创建JWT令牌
    
    参数:
        data (Dict[str, Any]): 令牌载荷数据
        
    返回:
        str: JWT令牌
    """
    to_encode = data.copy()
    
    # 设置过期时间
    expire = time.time() + JWT_EXPIRATION
    to_encode.update({"exp": expire})
    
    # 生成令牌
    encoded_jwt = jwt.encode(to_encode, JWT_SECRET, algorithm=JWT_ALGORITHM)
    return encoded_jwt

# JWT认证依赖
jwt_auth = JWTBearer() 